<?php

namespace app\common\model;

use app\common\library\helper;
use app\common\service\Goods as GoodsService;

/**
 * 商品模型
 * Class Goods
 * @package app\common\model
 */
class Goods extends BaseModel
{
    protected $name = 'goods';
    protected $append = ['goods_sales'];

    /**
     * 计算显示销量 (初始销量 + 实际销量)
     * @param $value
     * @param $data
     * @return mixed
     */
    public function getGoodsSalesAttr($value, $data)
    {
        return $data['sales_initial'] + $data['sales_actual'];
    }

    /**
     * 获取器：单独设置折扣的配置
     * @param $json
     * @return mixed
     */
    public function getAloneGradeEquityAttr($json)
    {
        return json_decode($json, true);
    }

    /**
     * 修改器：单独设置折扣的配置
     * @param $data
     * @return mixed
     */
    public function setAloneGradeEquityAttr($data)
    {
        return json_encode($data);
    }

    /**
     * 关联商品分类表
     * @return \think\model\relation\BelongsTo
     */
    public function category()
    {
        return $this->belongsTo('Category');
    }

    /**
     * 关联商品规格表
     * @return \think\model\relation\HasMany
     */
    public function sku()
    {
        return $this->hasMany('GoodsSku')->order(['goods_sku_id' => 'asc']);
    }

    /**
     * 关联商品规格关系表
     * @return \think\model\relation\BelongsToMany
     */
    public function specRel()
    {
        return $this->belongsToMany('SpecValue', 'GoodsSpecRel')->order(['id' => 'asc']);
    }

    /**
     * 关联商品图片表
     * @return \think\model\relation\HasMany
     */
    public function image()
    {
        return $this->hasMany('GoodsImage')->order(['id' => 'asc']);
    }

    /**
     * 关联运费模板表
     * @return \think\model\relation\BelongsTo
     */
    public function delivery()
    {
        return $this->BelongsTo('Delivery');
    }

    /**
     * 关联订单评价表
     * @return \think\model\relation\HasMany
     */
    public function commentData()
    {
        return $this->hasMany('Comment');
    }

    /**
     * 计费方式
     * @param $value
     * @return mixed
     */
    public function getGoodsStatusAttr($value)
    {
        $status = [10 => '出诊', 20 => '休息'];
        return ['text' => $status[$value], 'value' => $value];
    }

    /**
     * 获取商品列表
     * @param $param
     * @return mixed
     * @throws \think\exception\DbException
     */
    // public function getList($param)
    // {
    //     // 商品列表获取条件
    //     $params = array_merge([
    //         'status' => 10,         // 商品状态
    //         'category_id' => 0,     // 分类id
    //         'search' => '',         // 搜索关键词
    //         'sortType' => 'all',    // 排序类型
    //         'sortPrice' => false,   // 价格排序 高低
    //         'listRows' => 15,       // 每页数量
    //     ], $param);
    //     if (isset($params['is_doctor'])) {
    //         $w['is_doctor'] = '2';
    //     }else{
    //         $w['is_doctor'] = '1';
    //     }
    //     // 筛选条件
    //     $filter = [];
    //     $params['category_id'] > 0 && $filter['category_id'] = ['IN', Category::getSubCategoryId($params['category_id'])];
    //     $params['status'] > 0 && $filter['goods_status'] = $params['status'];
    //     if (!empty($params['mz_type']) && ($params['mz_type'] != "全部")) {
    //         $filter['mz_type'] = $params['mz_type'];
    //     }
    //     !empty($params['search']) && $filter['goods_name'] = ['like', '%' . trim($params['search']) . '%'];
    //     // 排序规则
    //     $sort = [];
    //     if ($params['sortType'] === 'all') {
    //         $sort = ['goods_sort', 'goods_id' => 'desc'];
    //     } elseif ($params['sortType'] === 'sales') {
    //         $sort = ['goods_sales' => 'desc'];
    //     } elseif ($params['sortType'] === 'price') {
    //         $sort = $params['sortPrice'] ? ['goods_max_price' => 'desc'] : ['goods_min_price' => 'asc'];
    //     }
    //     // 商品表名称
    //     $tableName = $this->getTable();
    //     // 多规格商品 最高价与最低价
    //     $GoodsSku = new GoodsSku;
    //     $minPriceSql = $GoodsSku->field(['MIN(goods_price)'])
    //         ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")->buildSql();
    //     $maxPriceSql = $GoodsSku->field(['MAX(goods_price)'])
    //         ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")->buildSql();
    //     // 执行查询
    //     $list = $this
    //         ->field(['*', '(sales_initial + sales_actual) as goods_sales',
    //             "$minPriceSql AS goods_min_price",
    //             "$maxPriceSql AS goods_max_price"
    //         ])
    //         ->with(['category', 'image.file', 'sku'])
    //         ->where('is_delete', '=', 0)
    //         ->where($filter)
    //         ->where($w)
    //         ->order($sort)
    //         ->paginate($params['listRows'], false, [
    //             'query' => \request()->request()
    //         ]);
    //     // 整理列表数据并返回
    //     return $this->setGoodsListData($list, true);
    // }
    public function getList($param)
    {
        // 商品列表获取条件
        $params = array_merge([
            'status'    => 10,        // 商品状态
            'category_id' => 0,       // 分类id
            'search'    => '',        // 搜索关键词
            'sortType'  => 'all',     // 排序类型
            'sortPrice' => false,     // 价格排序 高低
            'listRows'  => 15,        // 每页数量
            'soldout'   => null,      // 是否已售罄（1=已售罄；0/空=不限）
        ], $param);

        // 是否医生
        if (isset($params['is_doctor'])) {
            $w['is_doctor'] = '2';
        } else {
            $w['is_doctor'] = '1';
        }

        // 筛选条件
        $filter = [];
        $params['category_id'] > 0 && $filter['category_id']   = ['IN', Category::getSubCategoryId($params['category_id'])];
        $params['status']      > 0 && $filter['goods_status']  = $params['status'];
        if (!empty($params['mz_type']) && ($params['mz_type'] != "全部")) {
            $filter['mz_type'] = $params['mz_type'];
        }
        !empty($params['search']) && $filter['goods_name'] = ['like', '%' . trim($params['search']) . '%'];

        // 排序规则
        if ($params['sortType'] === 'all') {
            $sort = ['goods_sort', 'goods_id' => 'desc'];
        } elseif ($params['sortType'] === 'sales') {
            $sort = ['goods_sales' => 'desc'];
        } elseif ($params['sortType'] === 'price') {
            $sort = $params['sortPrice'] ? ['goods_max_price' => 'desc'] : ['goods_min_price' => 'asc'];
        } else {
            $sort = ['goods_sort', 'goods_id' => 'desc'];
        }

        // 表名
        $tableName = $this->getTable();

        // SKU 价格 & 库存汇总子查询
        $GoodsSku    = new GoodsSku;
        $minPriceSql = $GoodsSku->field(['MIN(goods_price)'])
            ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")->buildSql();
        $maxPriceSql = $GoodsSku->field(['MAX(goods_price)'])
            ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")->buildSql();
        $sumStockSql = $GoodsSku->field(['IFNULL(SUM(stock_num),0)'])
            ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")->buildSql();

        $query = $this->field([
                    '*',
                    '(sales_initial + sales_actual) as goods_sales',
                    "$minPriceSql AS goods_min_price",
                    "$maxPriceSql AS goods_max_price",
                    "$sumStockSql AS total_stock"
                ])
                ->with(['category', 'image.file', 'sku'])
                ->where('is_delete', '=', 0)
                ->where($filter)
                ->where($w);

        // 售罄筛选：soldout=1 => 库存=0；soldout=0 => 库存>0
        if (isset($params['soldout']) && $params['soldout'] !== '' && $params['soldout'] !== null) {
            $op = ((string)$params['soldout'] === '1') ? '=' : '>';
            // TP5 用字符串条件
            $query->where("( {$sumStockSql} ) {$op} 0");
            // TP6 可改成：$query->whereRaw("( {$sumStockSql} ) {$op} 0");
        }

        $list = $query->order($sort)
            ->paginate($params['listRows'], false, [
                'query' => \request()->request()
            ]);

        // 返回
        return $this->setGoodsListData($list, true);
    }
    // 小程序端获取商品列表
    
   
    public function getList12($param)
    {
        $params = array_merge([
            'status' => 10,
            'category_id' => 0,
            'search' => '',
            'sortType' => 'all',
            'sortPrice' => false,
            'listRows' => 15,
        ], $param);

        $filter = [];
        $params['category_id'] > 0 && $filter['category_id'] = ['IN', Category::getSubCategoryId($params['category_id'])];
        $params['status'] > 0 && $filter['goods_status'] = $params['status'];
        !empty($params['search']) && $filter['goods_name'] = ['like', '%' . trim($params['search']) . '%'];

        $sort = [];
        if ($params['sortType'] === 'all') {
            $sort = ['goods_sort', 'goods_id' => 'desc'];
        } elseif ($params['sortType'] === 'sales') {
            $sort = ['goods_sales' => 'desc'];
        } elseif ($params['sortType'] === 'price') {
            $sort = $params['sortPrice'] ? ['goods_max_price' => 'desc'] : ['goods_min_price' => 'asc'];
        }

        $tableName = $this->getTable();
        $GoodsSku = new GoodsSku;
        $minPriceSql = $GoodsSku->field(['MIN(goods_price)'])
            ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")->buildSql();
        $maxPriceSql = $GoodsSku->field(['MAX(goods_price)'])
            ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")->buildSql();

        // 获取未来8天的日期范围
        $today = date('Y-m-d');
        $endDate = date('Y-m-d', strtotime('+8 days'));
        $currentTime = date('H:i');

        // 子查询：获取未来8天内有排班的goods_id
        $subQuery = DB('goods_paiban')
            ->whereBetween('day', [$today, $endDate])
            ->distinct(true)
            ->column('goods_id');

        // 只查询子查询返回的 goods_id
        $filter['goods_id'] = ['IN', $subQuery];

        $list = $this
            ->field(['*', '(sales_initial + sales_actual) as goods_sales',
                "$minPriceSql AS goods_min_price",
                "$maxPriceSql AS goods_max_price",
                'content as con'
            ])
            ->with(['category1' => ['topLevelParent'], 'image.file', 'sku'])
            ->where('is_delete', '=', 0)
            ->where($filter)
            ->order($sort)
            ->paginate($params['listRows'], false, [
                'query' => \request()->request()
            ]);
        // dump($list);die;
        // 处理每个商品的排班信息
        $goodsIds = array_column($list->items(), 'goods_id');
        // $paibanData = DB('goods_paiban')
        //     ->whereIn('goods_id', $goodsIds)
        //     ->whereBetween('day', [$today, $endDate])
        //     ->order(['day' => 'asc', 'morning' => 'desc']) // 排序：按日期，上午优先
        //     ->select();
        $paibanData = DB('goods_paiban')
        ->whereIn('goods_id', $goodsIds)
        ->whereBetween('day', [$today, $endDate])
        ->group('goods_id, day, morning, afternoon') // 按指定字段去重
        ->order(['day' => 'asc', 'morning' => 'desc']) // 排序：按日期，上午优先
        ->select();
        // 将排班信息按照 goods_id 进行分组
        $groupedPaiban = [];
        foreach ($paibanData as $paiban) {
            $goodsId = $paiban['goods_id'];
            $isToday = ($paiban['day'] === $today); // 检查是否是当天
            $dayOfWeek = date('l', strtotime($paiban['day']));
            $dayOfWeekCn = $this->getChineseDayOfWeek($dayOfWeek);

            // 添加上午排班记录，过滤掉 remaining_num = 0
            if ((!$isToday || $currentTime <= '11:50') && $paiban['morning_num'] > 0) {
                $groupedPaiban[$goodsId][] = [
                    'day' => $paiban['day'],
                    'day_of_week' => $dayOfWeekCn,
                    'time' => '上午',
                    'remaining_num' => $paiban['morning_num'],
                ];
            }

            // 添加下午排班记录，过滤掉 remaining_num = 0
            if ((!$isToday || $currentTime <= '17:00') && $paiban['afternoon_num'] > 0) {
                $groupedPaiban[$goodsId][] = [
                    'day' => $paiban['day'],
                    'day_of_week' => $dayOfWeekCn,
                    'time' => '下午',
                    'remaining_num' => $paiban['afternoon_num'],
                ];
            }
        }

        // 将排班数据添加到每个商品的 `paiban` 字段中
        foreach ($list as &$item) {
            $item['paiban'] = isset($groupedPaiban[$item['goods_id']]) ? $groupedPaiban[$item['goods_id']] : [];
        }
        return $this->setGoodsListData($list, true);
    }
    // public function getList1($param)
    // {
    //     $params = array_merge([
    //         'status'      => 10,
    //         'category_id' => 0,
    //         'search'      => '',
    //         'sortType'    => 'all',
    //         'sortPrice'   => false,
    //         'listRows'    => 15,
    //     ], $param);
    //     $filter = [];
    //     if ($params['category_id'] > 0) {
    //         $filter['category_id'] = ['IN', Category::getSubCategoryId($params['category_id'])];
    //     }
        
    //     if ($params['status'] > 0) {
    //         $filter['goods_status'] = $params['status'];
    //     }
    //     if (!empty($params['search'])) {
    //         $filter['goods_name'] = ['like', '%' . trim($params['search']) . '%'];
    //     }
    //     $sort = [];
    //     if ($params['sortType'] === 'all') {
    //         $sort = ['goods_sort', 'goods_id' => 'desc'];
    //     } elseif ($params['sortType'] === 'sales') {
    //         $sort = ['goods_sales' => 'desc'];
    //     } elseif ($params['sortType'] === 'price') {
    //         $sort = $params['sortPrice'] ? ['goods_max_price' => 'desc'] : ['goods_min_price' => 'asc'];
    //     }
    
    //     $tableName = $this->getTable();
    //     $GoodsSku = new GoodsSku;
    //     $minPriceSql = $GoodsSku->field(['MIN(goods_price)'])
    //         ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")
    //         ->buildSql();
    //     $maxPriceSql = $GoodsSku->field(['MAX(goods_price)'])
    //         ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")
    //         ->buildSql();
    
    //     // 获取未来8天的日期范围
    //     $today       = date('Y-m-d');
    //     $endDate     = date('Y-m-d', strtotime('+8 days'));
    //     $currentTime = date('H:i');
    
    //     // 子查询：获取未来8天内存在排班记录的 goods_id（使用新表 goods_weekly_schedule）
    //     $subQuery = DB('goods_weekly_schedule')
    //         ->distinct(true)
    //         ->column('goods_id');
    //     $filter['goods_id'] = ['IN', $subQuery];
    //     $list = $this
    //         ->field([
    //             '*',
    //             '(sales_initial + sales_actual) as goods_sales',
    //             "$minPriceSql AS goods_min_price",
    //             "$maxPriceSql AS goods_max_price",
    //             'content as con'
    //         ])
    //         ->with(['category1' => ['topLevelParent'], 'image.file', 'sku'])
    //         ->where('is_delete', '=', 0)
    //         ->where($filter)
    //         ->order($sort)
    //         ->paginate($params['listRows'], false, [
    //             'query' => request()->request()
    //         ]);
    
    //     // 将分页结果转换为数组，以便修改其中的 data 部分
    //     // 查询所有商品的每周排班记录（新表 goods_weekly_schedule）
    //     $goodsIds = array_column($list->items(), 'goods_id');
    //     $weeklySchedules = DB('goods_weekly_schedule')
    //         ->whereIn('goods_id', $goodsIds)
    //         ->select();
    
    //     // 组织排班数据，按 goods_id 与 week_day（1～7）分组
    //     $groupedSchedule = [];
    //     foreach ($weeklySchedules as $schedule) {
    //         $goodsId = $schedule['goods_id'];
    //         $groupedSchedule[$goodsId][$schedule['week_day']] = $schedule;
    //     }
    
    //     // 构造未来8天的日期及对应的星期（1=周一, 7=周日）
    //     $scheduleDates = [];
    //     $dateIterator = new \DateTime($today);
    //     for ($i = 0; $i < 8; $i++) {
    //         $date = $dateIterator->format('Y-m-d');
    //         $weekDay = (int)$dateIterator->format('N'); // 1 ~ 7
    //         $scheduleDates[$date] = $weekDay;
    //         $dateIterator->modify('+1 day');
    //     }
    //     $listArray = $list->toArray();
    //     // dump($list->items());die;
    //     // 遍历商品数据（数组中的 data 部分），添加 paiban 排班信息
    //     foreach ($list->items() as $item) {
    //         $goodsId = $item['goods_id']; // 读取时可以用数组方式
    //         $paiban = [];
        
    //         foreach ($scheduleDates as $date => $weekDay) {
    //             $dayOfWeekCn = $this->getChineseDayOfWeek(date('l', strtotime($date)));
    //             if (isset($groupedSchedule[$goodsId][$weekDay])) {
    //                 $sch = $groupedSchedule[$goodsId][$weekDay];
        
    //                 // 上午：截止时间 11:50
    //                 $morningAvailable = ($sch['morning'] == 1 && $sch['morning_num'] > 0);
    //                 if ($date === $today && $currentTime > '11:50') {
    //                     $morningAvailable = false;
    //                 }
    //                 if ($morningAvailable) {
    //                     $paiban[] = [
    //                         'day'           => $date,
    //                         'day_of_week'   => $dayOfWeekCn,
    //                         'time'          => '上午',
    //                         'remaining_num' => $sch['morning_num'],
    //                     ];
    //                 }
        
    //                 // 下午
    //                 $afternoonAvailable = ($sch['afternoon'] == 1 && $sch['afternoon_num'] > 0);
    //                 if ($date === $today && $currentTime > '17:00') {
    //                     $afternoonAvailable = false;
    //                 }
    //                 if ($afternoonAvailable) {
    //                     $paiban[] = [
    //                         'day'           => $date,
    //                         'day_of_week'   => $dayOfWeekCn,
    //                         'time'          => '下午',
    //                         'remaining_num' => $sch['afternoon_num'],
    //                     ];
    //                 }
        
    //                 // 夜间
    //                 $nightAvailable = ($sch['night'] == 1 && $sch['night_num'] > 0);
    //                 if ($date === $today && $currentTime > '22:00') {
    //                     $nightAvailable = false;
    //                 }
    //                 if ($nightAvailable) {
    //                     $paiban[] = [
    //                         'day'           => $date,
    //                         'day_of_week'   => $dayOfWeekCn,
    //                         'time'          => '夜间',
    //                         'remaining_num' => $sch['night_num'],
    //                     ];
    //                 }
        
    //             } else {
    //                 $paiban[] = [
    //                     'day'           => $date,
    //                     'day_of_week'   => $dayOfWeekCn,
    //                     'time'          => '无号',
    //                     'remaining_num' => 0,
    //                 ];
    //             }
    //         }
    //         // 正确赋值方式：使用 setAttr 或对象属性
    //         $item->setAttr('paiban', $paiban);
    //     }
    //     unset($item);
    //     // dump($list);die;
    //     return $this->setGoodsListData($list, true);
    // }
    // 修改之前的代码
    // public function getList1($param)
    // {
    //     $params = array_merge([
    //         'status'      => 10,
    //         'category_id' => 0,
    //         'search'      => '',
    //         'sortType'    => 'all',
    //         'sortPrice'   => false,
    //         'listRows'    => 15,
    //     ], $param);

    //     $filter = [];
    //     if ($params['category_id'] > 0) {
    //         $filter['category_id'] = ['IN', Category::getSubCategoryId($params['category_id'])];
    //     }
    //     if ($params['status'] > 0) {
    //         $filter['goods_status'] = $params['status'];
    //     }
    //     if (!empty($params['search'])) {
    //         $filter['goods_name'] = ['like', '%' . trim($params['search']) . '%'];
    //     }
    //     $sort = [];
    //     if ($params['sortType'] === 'all') {
    //         $sort = ['goods_sort', 'goods_id' => 'desc'];
    //     } elseif ($params['sortType'] === 'sales') {
    //         $sort = ['goods_sales' => 'desc'];
    //     } elseif ($params['sortType'] === 'price') {
    //         $sort = $params['sortPrice'] ? ['goods_max_price' => 'desc'] : ['goods_min_price' => 'asc'];
    //     }

    //     $tableName = $this->getTable();
    //     $GoodsSku = new GoodsSku;
    //     $minPriceSql = $GoodsSku->field(['MIN(goods_price)'])
    //         ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")
    //         ->buildSql();
    //     $maxPriceSql = $GoodsSku->field(['MAX(goods_price)'])
    //         ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")
    //         ->buildSql();

    //     // 如果有分类，则查询排班和paiban信息
    //     if ($params['category_id'] > 0) {
    //         $subQuery = DB('goods_weekly_schedule')
    //             ->distinct(true)
    //             ->column('goods_id');
    //         $filter['goods_id'] = ['IN', $subQuery];
    //     }

    //     $list = $this
    //         ->field([
    //             '*',
    //             '(sales_initial + sales_actual) as goods_sales',
    //             "$minPriceSql AS goods_min_price",
    //             "$maxPriceSql AS goods_max_price",
    //             'content as con'
    //         ])
    //         ->with(['category1' => ['topLevelParent'], 'image.file', 'sku'])
    //         ->where('is_delete', '=', 0)
    //         ->where($filter)
    //         ->order($sort)
    //         ->paginate($params['listRows'], false, [
    //             'query' => request()->request()
    //         ]);

    //     // 如果没有分类，不处理排班直接返回
    //     if ($params['category_id'] == 0) {
    //         return $this->setGoodsListData($list, true);
    //     }

    //     // 以下是排班处理逻辑（category_id > 0 才执行）
    //     $today       = date('Y-m-d');
    //     $endDate     = date('Y-m-d', strtotime('+8 days'));
    //     $currentTime = date('H:i');

    //     $goodsIds = array_column($list->items(), 'goods_id');
    //     $weeklySchedules = DB('goods_weekly_schedule')
    //         ->whereIn('goods_id', $goodsIds)
    //         ->select();

    //     $groupedSchedule = [];
    //     foreach ($weeklySchedules as $schedule) {
    //         $groupedSchedule[$schedule['goods_id']][$schedule['week_day']] = $schedule;
    //     }

    //     $scheduleDates = [];
    //     $dateIterator = new \DateTime($today);
    //     for ($i = 0; $i < 8; $i++) {
    //         $date = $dateIterator->format('Y-m-d');
    //         $weekDay = (int)$dateIterator->format('N');
    //         $scheduleDates[$date] = $weekDay;
    //         $dateIterator->modify('+1 day');
    //     }

    //     foreach ($list->items() as $item) {
    //         $goodsId = $item['goods_id'];
    //         $paiban = [];

    //         foreach ($scheduleDates as $date => $weekDay) {
    //             $dayOfWeekCn = $this->getChineseDayOfWeek(date('l', strtotime($date)));
    //             if (isset($groupedSchedule[$goodsId][$weekDay])) {
    //                 $sch = $groupedSchedule[$goodsId][$weekDay];

    //                 if (($sch['morning'] == 1 && $sch['morning_num'] > 0) && ($date !== $today || $currentTime <= '11:50')) {
    //                     $paiban[] = [
    //                         'day'           => $date,
    //                         'day_of_week'   => $dayOfWeekCn,
    //                         'time'          => '上午',
    //                         'remaining_num' => $sch['morning_num'],
    //                     ];
    //                 }
    //                 if (($sch['afternoon'] == 1 && $sch['afternoon_num'] > 0) && ($date !== $today || $currentTime <= '17:00')) {
    //                     $paiban[] = [
    //                         'day'           => $date,
    //                         'day_of_week'   => $dayOfWeekCn,
    //                         'time'          => '下午',
    //                         'remaining_num' => $sch['afternoon_num'],
    //                     ];
    //                 }
    //                 if (($sch['night'] == 1 && $sch['night_num'] > 0) && ($date !== $today || $currentTime <= '22:00')) {
    //                     $paiban[] = [
    //                         'day'           => $date,
    //                         'day_of_week'   => $dayOfWeekCn,
    //                         'time'          => '夜间',
    //                         'remaining_num' => $sch['night_num'],
    //                     ];
    //                 }
    //             } else {
    //                 $paiban[] = [
    //                     'day'           => $date,
    //                     'day_of_week'   => $dayOfWeekCn,
    //                     'time'          => '无号',
    //                     'remaining_num' => 0,
    //                 ];
    //             }
    //         }

    //         $item->setAttr('paiban', $paiban);
    //     }

    //     return $this->setGoodsListData($list, true);
    // }
    public function getList1($param)
    {
        $params = array_merge([
            'status'      => 10,
            'category_id' => 0,
            'search'      => '',
            'sortType'    => 'all',
            'sortPrice'   => false,
            'listRows'    => 15,
        ], $param);

        $filter = [];
        if ($params['category_id'] > 0) {
            $filter['category_id'] = ['IN', Category::getSubCategoryId($params['category_id'])];
        }
        if ($params['status'] > 0) {
            $filter['goods_status'] = $params['status'];
        }
        if (!empty($params['search'])) {
            $filter['goods_name'] = ['like', '%' . trim($params['search']) . '%'];
        }
        $sort = [];
        if ($params['sortType'] === 'all') {
            $sort = ['goods_sort', 'goods_id' => 'desc'];
        } elseif ($params['sortType'] === 'sales') {
            $sort = ['goods_sales' => 'desc'];
        } elseif ($params['sortType'] === 'price') {
            $sort = $params['sortPrice'] ? ['goods_max_price' => 'desc'] : ['goods_min_price' => 'asc'];
        }

        $tableName = $this->getTable();
        $GoodsSku = new GoodsSku;
        $minPriceSql = $GoodsSku->field(['MIN(goods_price)'])
            ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")
            ->buildSql();
        $maxPriceSql = $GoodsSku->field(['MAX(goods_price)'])
            ->where('goods_id', 'EXP', "= `$tableName`.`goods_id`")
            ->buildSql();

        // 如果有分类，则查询排班存在的医生
        if ($params['category_id'] > 0) {
            $subQuery = DB('goods_weekly_schedule')->distinct(true)->column('goods_id');
            $filter['goods_id'] = ['IN', $subQuery];
        }

        $list = $this
            ->field([
                '*',
                '(sales_initial + sales_actual) as goods_sales',
                "$minPriceSql AS goods_min_price",
                "$maxPriceSql AS goods_max_price",
                'content as con'
            ])
            ->with(['category1' => ['topLevelParent'], 'image.file', 'sku'])
            ->where('is_delete', '=', 0)
            ->where($filter)
            ->order($sort)
            ->paginate($params['listRows'], false, [
                'query' => request()->request()
            ]);

        // 若未按分类筛选，直接返回原逻辑
        if ($params['category_id'] == 0) {
            return $this->setGoodsListData($list, true);
        }

        /** ====== 新增：可覆盖当前时间 + 时区固定 ====== */
        $tz      = new \DateTimeZone('Asia/Shanghai');
        
        // $tz      = '__now=2025-08-26 16:29:00';
        // 支持通过 ?__now=2025-08-26 16:29:00 覆盖当前时间做联调
        $nowArg  = request()->get('__now', '');
        $now     = $nowArg ? new \DateTime($nowArg, $tz) : new \DateTime('now', $tz);
        $today   = $now->format('Y-m-d');

        // 截止时间（仅对“今天”生效）
        $cutMorning   = new \DateTime('12:00', $tz);
        $cutAfternoon = new \DateTime('17:00', $tz);
        $cutNight     = new \DateTime('19:30', $tz);

        // 未来 8 天（含今天）
        $scheduleDates = [];
        $dateIterator  = new \DateTime($today, $tz);
        for ($i = 0; $i < 8; $i++) {
            $date = $dateIterator->format('Y-m-d');
            $weekDay = (int)$dateIterator->format('N'); // 1-7
            $scheduleDates[$date] = $weekDay;
            $dateIterator->modify('+1 day');
        }

        // 拉取这些医生的周排班
        $goodsIds = array_column($list->items(), 'goods_id');
        if (empty($goodsIds)) {
            return $this->setGoodsListData($list, true);
        }
        $weeklySchedules = DB('goods_weekly_schedule')
            ->whereIn('goods_id', $goodsIds)
            ->select();
        // 分组：$groupedSchedule[goods_id][week_day] = row
        $groupedSchedule = [];
        foreach ($weeklySchedules as $schedule) {
            $groupedSchedule[$schedule['goods_id']][$schedule['week_day']] = $schedule;
        }

        // 生成前端需要的排班展示
        foreach ($list->items() as $item) {
            $goodsId = $item['goods_id'];
            $paiban  = [];

            foreach ($scheduleDates as $date => $weekDay) {
                $dayOfWeekCn = $this->getChineseDayOfWeek(date('l', strtotime($date)));

                if (!isset($groupedSchedule[$goodsId][$weekDay])) {
                    // 无排班记录
                    $paiban[] = [
                        'day'           => $date,
                        'day_of_week'   => $dayOfWeekCn,
                        'time'          => '无号',
                        'remaining_num' => 0,
                    ];
                    continue;
                }

                $sch = $groupedSchedule[$goodsId][$weekDay];
                $isToday = ($date === $today);

                // 上午
                if ($sch['morning'] == 1) {
                    $allow = !$isToday || ($now <= $cutMorning);
                    if ($allow) {
                        $paiban[] = [
                            'day'           => $date,
                            'day_of_week'   => $dayOfWeekCn,
                            'time'          => '上午',
                            'remaining_num' => $sch['morning_num'],
                        ];
                    }
                }

                // 下午
                if ($sch['afternoon'] == 1) {
                    $allow = !$isToday || ($now <= $cutAfternoon);
                    if ($allow) {
                        $paiban[] = [
                            'day'           => $date,
                            'day_of_week'   => $dayOfWeekCn,
                            'time'          => '下午',
                            'remaining_num' => $sch['afternoon_num'],
                        ];
                    }
                }

                // 夜间
                if ($sch['night'] == 1) {
                    $allow = !$isToday || ($now <= $cutNight);
                    if ($allow) {
                        $paiban[] = [
                            'day'           => $date,
                            'day_of_week'   => $dayOfWeekCn,
                            'time'          => '夜间',
                            'remaining_num' => $sch['night_num'],
                        ];
                    }
                }
            }

            $item->setAttr('paiban', $paiban);
        }

        return $this->setGoodsListData($list, true);
    }
    private function getChineseDayOfWeek($dayEn)
    {
        $weekdays = [
            'Sunday'    => '周日',
            'Monday'    => '周一',
            'Tuesday'   => '周二',
            'Wednesday' => '周三',
            'Thursday'  => '周四',
            'Friday'    => '周五',
            'Saturday'  => '周六',
        ];
        return isset($weekdays[$dayEn]) ? $weekdays[$dayEn] : $dayEn;
    }
    public function category1()
    {
        return $this->belongsTo(Category::class, 'category_id')->with(['topLevelParent', 'subCategories']);
    }
    /**
     * 设置商品展示的数据
     * @param $data
     * @param bool $isMultiple
     * @param callable $callback
     * @return mixed
     */
    protected function setGoodsListData($data, $isMultiple = true, callable $callback = null)
    {
        if (!$isMultiple) $dataSource = [&$data]; else $dataSource = &$data;
        // 整理商品列表数据
        foreach ($dataSource as &$goods) {
            // 商品主图
            $goods['goods_image'] = $goods['image'][0]['file_path'];
            // 商品默认规格
            $goods['goods_sku'] = $goods['sku'][0];
            // 回调函数
            is_callable($callback) && call_user_func($callback, $goods);
        }
        return $data;
    }
    /**
     * 整理商品列表数据，并附加一些字段
     *
     * @param mixed $data
     * @param bool $isMultiple
     * @param callable|null $callback
     * @return mixed
     */

    /**
     * 根据商品id集获取商品列表
     * @param array $goodsIds
     * @param null $status
     * @return false|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getListByIds($goodsIds, $status = null)
    {
      // 筛选条件
        $filter = ['goods_id' => ['in', $goodsIds]];
        $status > 0 && $filter['goods_status'] = $status;
        if (!empty($goodsIds)) {
            $this->orderRaw('field(goods_id, ' . implode(',', $goodsIds) . ')');
        }
        // 获取商品列表数据
//        ['category', 'image.file', 'sku', 'spec_rel.spec', 'delivery.rule']
        $data = $this->field(['content'], true)
            ->with(['category', 'image.file', 'sku'])
            ->where($filter)
            ->select();
        // 整理列表数据并返回
        return $this->setGoodsListData($data, true);

    }

    /**
     * 商品多规格信息
     * @param \think\Collection $specRel
     * @param \think\Collection $skuData
     * @return array
     */
    public function getManySpecData($specRel, $skuData)
    {

        // spec_attr
        $specAttrData = [];
        foreach ($specRel as $item) {
            if (!isset($specAttrData[$item['spec_id']])) {
                $specAttrData[$item['spec_id']] = [
                    'group_id' => $item['spec']['spec_id'],
                    'group_name' => $item['spec']['spec_name'],
                    'spec_items' => [],
                ];
            }
            $specAttrData[$item['spec_id']]['spec_items'][] = [
                'item_id' => $item['spec_value_id'],
                'spec_value' => $item['spec_value'],
            ];
        }

        // spec_list
        $specListData = [];
        foreach ($skuData as $item) {
            $image = (isset($item['image']) && !empty($item['image'])) ? $item['image'] : ['file_id' => 0, 'file_path' => ''];
            $specListData[] = [
                'goods_sku_id' => $item['goods_sku_id'],
                'spec_sku_id' => $item['spec_sku_id'],
                'rows' => [],
                'form' => [
                    'image_id' => $image['file_id'],
                    'image_path' => $image['file_path'],
                    'goods_no' => $item['goods_no'],
                    'goods_price' => $item['goods_price'],
                    'goods_weight' => $item['goods_weight'],
                    'line_price' => $item['line_price'],
                    'stock_num' => $item['stock_num'],
                ],
            ];
        }
        return ['spec_attr' => array_values($specAttrData), 'spec_list' => $specListData];
    }

    /**
     * 多规格表格数据
     * @param $goods
     * @return array
     */
    public function getManySpecTable(&$goods)
    {
        $specData = $this->getManySpecData($goods['spec_rel'], $goods['sku']);
        $totalRow = count($specData['spec_list']);
        foreach ($specData['spec_list'] as $i => &$sku) {
            $rowData = [];
            $rowCount = 1;
            foreach ($specData['spec_attr'] as $attr) {
                $skuValues = $attr['spec_items'];
                $rowCount *= count($skuValues);
                $anInterBankNum = ($totalRow / $rowCount);
                $point = (($i / $anInterBankNum) % count($skuValues));
                if (0 === ($i % $anInterBankNum)) {
                    $rowData[] = [
                        'rowspan' => $anInterBankNum,
                        'item_id' => $skuValues[$point]['item_id'],
                        'spec_value' => $skuValues[$point]['spec_value']
                    ];
                }
            }
            $sku['rows'] = $rowData;
        }
        return $specData;
    }

    /**
     * 获取商品详情
     * @param $goodsId
     * @return static
     */
    public static function detail($goodsId)
    {
        /* @var $model self */
        $model = (new static)->with([
            'category',
            'image.file',
            'sku.image',
            'spec_rel.spec',
        ])->where('goods_id', '=', $goodsId)
            ->find();
        if (empty($model)) {
            return $model;
        }
        // 整理商品数据并返回
        return $model->setGoodsListData($model, false);
    }

    /**
     * 指定的商品规格信息
     * @param static $goods 商品详情
     * @param int $specSkuId
     * @return array|bool
     */
    public static function getGoodsSku($goods, $specSkuId)
    {
        // 获取指定的sku
        $goodsSku = [];
        foreach ($goods['sku'] as $item) {
            if ($item['spec_sku_id'] == $specSkuId) {
                $goodsSku = $item;
                break;
            }
        }
        if (empty($goodsSku)) {
            return false;
        }
        // 多规格文字内容
        $goodsSku['goods_attr'] = '';
        if ($goods['spec_type'] == 20) {
            $specRelData = helper::arrayColumn2Key($goods['spec_rel'], 'spec_value_id');
            $attrs = explode('_', $goodsSku['spec_sku_id']);
            foreach ($attrs as $specValueId) {
                $goodsSku['goods_attr'] .= $specRelData[$specValueId]['spec']['spec_name'] . ':'
                    . $specRelData[$specValueId]['spec_value'] . '; ';
            }
        }
        return $goodsSku;
    }

}
